using System;
using System.IO;

using Toenda.Foundation;

namespace Toenda.Foundation.Audio {
	/// <summary>
	/// Summary description for mp3info.
	/// </summary>
	public class Mp3Info {
		private string _filename;

		private long _fileSize;
		private long _length; // in seconds

		private ID3v1 _id3v1;
		private ID3v2 _id3v2;
		private MPEG _mpeg;

		private bool _hasID3v1;
		private bool _hasID3v2;

		/// <summary>
		/// Initializes a new instance of the <see cref="Mp3Info"/> class.
		/// </summary>
		public Mp3Info() {
			this._Init();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="Mp3Info"/> class.
		/// </summary>
		/// <param name="fileName">Name of the file.</param>
		public Mp3Info(string fileName) {
			this._Init();
			this._filename = fileName;
		}

		/// <summary>
		/// Gets or sets the filename.
		/// </summary>
		/// <value>The filename.</value>
		public string Filename {
			get { return this._filename; }
			set { this._filename = value; }
		}

		/// <summary>
		/// Gets or sets the size of the file.
		/// </summary>
		/// <value>The size of the file.</value>
		public long FileSize {
			get { return this._fileSize; }
			set { this._fileSize = value; }
		}

		/// <summary>
		/// Gets or sets the length.
		/// </summary>
		/// <value>The length.</value>
		public long Length {
			get { return this._length; }
			set { this._length = value; }
		}

		/// <summary>
		/// Gets or sets the I D3V1.
		/// </summary>
		/// <value>The I D3V1.</value>
		public ID3v1 ID3v1 {
			get { return this._id3v1; }
			set { this._id3v1 = value; }
		}

		/// <summary>
		/// Gets or sets the I D3V2.
		/// </summary>
		/// <value>The I D3V2.</value>
		public ID3v2 ID3v2 {
			get { return this._id3v2; }
			set { this._id3v2 = value; }
		}

		/// <summary>
		/// Gets or sets the MPEG.
		/// </summary>
		/// <value>The MPEG.</value>
		public MPEG Mpeg {
			get { return this._mpeg; }
			set { this._mpeg = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance has I D3V1.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance has I D3V1; otherwise, <c>false</c>.
		/// </value>
		public bool HasID3v1 {
			get { return this._hasID3v1; }
			set { this._hasID3v1 = value; }
		}

		/// <summary>
		/// Gets or sets a value indicating whether this instance has I D3V2.
		/// </summary>
		/// <value>
		/// 	<c>true</c> if this instance has I D3V2; otherwise, <c>false</c>.
		/// </value>
		public bool HasID3v2 {
			get { return this._hasID3v2; }
			set { this._hasID3v2 = value; }
		}

		/// <summary>
		/// Inits this instance.
		/// </summary>
		private void _Init() {
			this._filename = "";
		}

		/// <summary>
		/// Calculates the length.
		/// </summary>
		private void _CalculateLength() {
			FileInfo fi = new FileInfo(this._filename);

			this._fileSize = fi.Length;
			this._mpeg.audioBytes = this._fileSize - this._mpeg.headerPosition;

			try {
				int bitrate = System.Convert.ToInt32(this._mpeg.Bitrate);

				if(bitrate > 0) {
					if(this.ID3v1.HasTag) {
						this._length = ( ( this._mpeg.audioBytes - 128 ) * 8 ) / ( 1000 * bitrate );
					}
					else {
						this._length = ( this._mpeg.audioBytes * 8 ) / ( 1000 * bitrate );
					}
				}
			}
			catch(Exception) {
				this._length = 0;
			}
		}

		/// <summary>
		/// Reads all.
		/// </summary>
		public void ReadAll() {
			if(this._filename.IsNullOrTrimmedEmpty()) {
				throw new ArgumentException("Please enter a filename...", "fileName");
			}
			else {
				this.ReadAll(this._filename);
			}
		}

		/// <summary>
		/// Reads all.
		/// </summary>
		/// <param name="fileName">Name of the file.</param>
		public void ReadAll(string fileName) {
			this._filename = fileName;

			if(this._filename.IsNullOrTrimmedEmpty()) {
				throw new ArgumentException("Please enter a filename...", "fileName");
			}
			else {
				this.ReadID3v1(this._filename);
				this.ReadID3v2(this._filename);
				this.ReadMPEG(this._filename);
				this._CalculateLength();
			}
		}

		/// <summary>
		/// Reads the I D3V1.
		/// </summary>
		public void ReadID3v1() {
			if(this._filename.IsNullOrTrimmedEmpty()) {
				throw new ArgumentException("Please enter a filename...", "fileName");
			}
			else {
				this.ReadID3v1(this._filename);
			}
		}

		/// <summary>
		/// Reads the I D3V1.
		/// </summary>
		/// <param name="file">The file.</param>
		public void ReadID3v1(string file) {
			// read id3 stuff
			this._id3v1 = new ID3v1(file);
			this._id3v1.Read();
			this._hasID3v1 = this._id3v1.HasTag;
		}

		/// <summary>
		/// Reads the I D3V2.
		/// </summary>
		public void ReadID3v2() {
			if(this._filename.IsNullOrTrimmedEmpty()) {
				throw new ArgumentException("Please enter a filename...", "fileName");
			}
			else {
				this.ReadID3v2(this._filename);
			}
		}

		/// <summary>
		/// Reads the I D3V2.
		/// </summary>
		/// <param name="file">The file.</param>
		public void ReadID3v2(string file) {
			// read id3 stuff
			this._id3v2 = new ID3v2(file);
			this._id3v2.Read();
			this._hasID3v2 = this._id3v2.hasTag;
		}

		/// <summary>
		/// Reads the MPEG.
		/// </summary>
		public void ReadMPEG() {
			if(this._filename.IsNullOrTrimmedEmpty()) {
				throw new ArgumentException("Please enter a filename...", "fileName");
			}
			else {
				this.ReadMPEG(this._filename);
			}
		}

		/// <summary>
		/// Reads the MPEG.
		/// </summary>
		/// <param name="file">The file.</param>
		public void ReadMPEG(string file) {
			// read id3 stuff
			this._mpeg = new MPEG(file);
			this._mpeg.Read();
		}
	}
}
